﻿using eSSP_example.Cpi;
using eSSP_example.Entity;
using log4net.Core;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace eSSP_example.Classes
{
    public class CCpi
    {
        //  The number of channels being used in this dataset.
        int m_NumberOfChannels;

        //  A variable to hold the type of the unit, obtained in setup request
        char m_UnitType;

        //  A list of dataset data, sorted by value. Holds the info on channel number, value, currency,
        //  level and whether it is being recycled.
        List<ChannelData> m_UnitDataList;

        //  Hopper List from the device.
        List<Hopper> hopperList;

        string strSerialNumber;

        ApiPaymentDevice cls_ApiPaymentDevice;

        /// <summary>
        /// 
        /// </summary>
        public CCpi() {

            m_NumberOfChannels = 0;

            cls_ApiPaymentDevice = new ApiPaymentDevice();

            m_UnitDataList = new List<ChannelData>();

            hopperList = new List<Hopper>();
        }

        //  access to number of channels
        public int NumberOfChannels
        {
            get { return m_NumberOfChannels; }

            set { m_NumberOfChannels = value; }
        }

        //  access to the unit's type
        public char UnitType
        {
            get { return m_UnitType; }
        }

        //  access to the data in the dataset
        public List<ChannelData> UnitDataList
        {
            get { return m_UnitDataList; }
        }

        //  get a channel value
        public int GetChannelValue(int channelNum)
        {
            if  (channelNum > 0 && channelNum <= m_NumberOfChannels)
            {
                foreach (ChannelData d in m_UnitDataList)
                {
                    if (d.Channel == channelNum)
                        return  d.Value;
                }
            }

            return  -1;
        }

        //  The enable command allows the validator to receive and act on commands.
        public void EnableValidator(TextBox log = null)
        {
            if  (log != null)
                log.AppendText("Cpi enabled\r\n");
        }

        // Empty device moves all the coins in the device to the cashbox using command EMPTY ALL. It then
        // sets the channel levels to 0.
        public void EmptyDevice(TextBox log = null)
        {
            ClsApiClass.GetInstance().Cls_emptyHoppers(0xFF);

            if  (log != null)
            {
                log.AppendText("Emptying all stored coins to cashbox...\r\n");

                foreach (ChannelData d in m_UnitDataList)
                    d.Level = 0;
            }
        }

        //  Disable command stops the unit accepting commands and acting on them.
        public void DisableValidator(TextBox log = null)
        {
            //  check response
            if  (log != null)
                log.AppendText("Cpi disabled\r\n");
        }

        //  The reset command instructs the validator to restart
        //  (same effect as switching on and off)
        public void Reset(TextBox log = null)
        {
            ClsApiClass.GetInstance().Cls_restartDevice();
        }

        //  This uses the PAYOUT AMOUNT command to payout a value specified by the param amountToPayout.
        //  Protocol 6+ - We can use an option byte to test whether the payout is possible (0x19), and if
        //  it is then we can resend with the option byte 0x58 to do the payout.
        public bool PayoutAmount(int amountToPayout, char[] currency, bool test = false, TextBox log = null)
        {
            int     result;
            string  strDispenseAmount;

            result = ClsApiClass.GetInstance().Cls_dispenseAmount(amountToPayout);

            strDispenseAmount = "Cls_dispenseAmount, amountToPay = " + amountToPayout +
                ",result = " + result.ToString("X");

            Console.WriteLine(strDispenseAmount);

            return  true;
        }

        /// <summary>
        ///     PayoutBydenominationV2
        /// </summary>
        /// <param name="numberOfCoins"></param>
        /// <param name="log"></param>
        public void PayoutBydenominationV2(byte[] numberOfCoins, TextBox log = null)
        {
            ClsApiClass.GetInstance().Cls_dispenseFromHoppers(numberOfCoins);

            if  (log != null)
                log.AppendText("Paying out by denomination...\r\n");
        }

        //  Payout by denomination. This function allows a developer to payout specified amounts of certain
        //  coins. Due to the variable length of the data that could be passed to the function, the user 
        //  passes an array containing the data to payout and the length of that array along with the number
        //  of denominations they are paying out.
        public void PayoutByDenomination(byte numDenoms, byte[] data, byte dataLength, TextBox log = null)
        {
            //  First is the command byte
            PayAction       payAction;
            List<PayAction> actions = new List<PayAction>();
            int             numDenom;
            int             valueDenom;
            string          strCurrencyDenom;
            byte[] curArray = new byte[3];

            if  (dataLength < numDenoms * 9)
                return;

            for (int i = 0; i < numDenoms; i++)
            {
                //  get num of denom
                numDenom = (int)(data[i * 9] << 8 + data[i * 9 + 1]);

                //  get value of denom
                valueDenom = (int)(data[i * 9 + 2] << 24 + data[i * 9 + 3] << 16 +
                    data[i * 9 + 4] << 8 + data[i * 9 + 5]);

                curArray[0] = data[i * 9 + 6];
                curArray[1] = data[i * 9 + 7];
                curArray[2] = data[i * 9 + 8];

                //  get currency of denom
                strCurrencyDenom = System.Text.Encoding.UTF8.GetString(curArray);

                payAction = new PayAction();
                payAction.numDenom = numDenom;
                payAction.valueDenom = valueDenom;
                payAction.currencyDenom =   strCurrencyDenom;

                actions.Add(payAction);
            }

            foreach (var action in actions)
            {
                
            }

            if  (log != null)
                log.AppendText("Paying out by denomination...\r\n");
        }

        //  This function uses the command SMARTY EMPTY which empties all the coins to the cashbox but keeps a 
        //  count of what was put in, the data of what coins were emptied can be accessed with the command
        //  CASHBOX PAYOUT OPERATION DATA
        public void SmartEmpty(TextBox log = null)
        {
            ClsApiClass.GetInstance().Cls_emptyHoppers(0xFF);

            if  (log != null) 
                log.AppendText("SMART empyting...\r\n");
        }

        //  This uses the SET COIN AMOUNT command to increase a channel level by passing over the channel and the amount to increment by
        public void SetCoinLevelsByChannel(int channel, short amount, TextBox log = null)
        {
            
        }

        /// <summary>
        ///     getHopperIdFromCoinValue
        /// </summary>
        /// <param name="coinValue"></param>
        /// <returns></returns>
        private int getHopperIdFromCoinValue(int coinValue)
        {
            int hopperId = 0;

            foreach (ChannelData d in m_UnitDataList)
            {
                if (d.Value == coinValue)
                {
                    hopperId = d.ChannelId;
                }
            }

            return  hopperId;
        }

        //  This uses the GET COIN AMOUNT command to query the validator on a
        //  specified coin it has stored, it returns
        //  the level as an int.
        public short CheckCoinLevel(int coinValue, char[] currency, TextBox log = null)
        {
            int     result_value = 0;
            short   u16InventoryValue = 0;

            //  S1: get HopperNo from Coin Value
            int  hopperId = getHopperIdFromCoinValue(coinValue);

            if  (hopperId == 0)
            {
                return  0;
            }

            //  S2: get Coin Level from HopperNo
            result_value = ClsApiClass.GetInstance().Cls_getHopperInventory((byte)hopperId,
                    ref u16InventoryValue);

            Console.WriteLine("CheckCoinLevel, coinValue = " + coinValue + ",hopperId = " + hopperId +
                ",Coin Level = " + u16InventoryValue);

            if (result_value == ReturnValue.RET_SUCCESS)
            {
                return  u16InventoryValue;
            }

            return  0;
        }

        //  This function just updates all the coin levels in the list
        public void UpdateData(TextBox log = null)
        {
            foreach (ChannelData d in m_UnitDataList)
            {
                d.Level = CheckCoinLevel(d.Value, d.Currency, log);

                IsCoinRecycling(d.Value, d.Currency, ref d.Recycling);
            }
        }

        //  This function uses the GET ROUTING command to see if a specified coin is recycling. The
        //  caller passes a bool across which is set by the function.
        public void IsCoinRecycling(int coinValue, char[] currency, ref bool response, TextBox log = null)
        {
            response = true;

            return;           
        }

        //  This function returns a member of the internal array to check whether a channel is
        //  recycling, this can't be called before setup request or it will be inaccurate.
        public bool IsChannelRecycling(int channel, TextBox log = null)
        {
            if (channel > 0 && channel <= m_NumberOfChannels)
            {
                foreach (ChannelData d in m_UnitDataList)
                {
                    if (d.Channel == channel)
                    {
                        if (log != null) 
                            log.AppendText("Channel " + channel + " recycling status: " + d.Recycling.ToString() + "\r\n");

                        return  d.Recycling;
                    }
                }
            }

            return  false;
        }

        //  
        //  This function uses the setup request command to get all the
        //  information about the validator. It can optionally
        //  output to a specified textbox.
        public void HopperSetupRequest(TextBox log = null)
        {
            Hopper __cpiHopper;

            StringBuilder sbDisplay = new StringBuilder(1000);
            sbDisplay.Append("Unit Type: ");
            m_UnitType = (char)0x04;

            switch (m_UnitType)
            {
                case (char)0x00: sbDisplay.Append("Validator"); break;
                case (char)0x03: sbDisplay.Append("SMART Hopper"); break;
                case (char)0x04: sbDisplay.Append("Cpi Hopper"); break;
                case (char)0x06: sbDisplay.Append("SMART Payout"); break;
                case (char)0x07: sbDisplay.Append("NV11"); break;
                case (char)0x09: sbDisplay.Append("SMART Coin System"); break;
                default:         sbDisplay.Append("Unknown Type"); break;
            }
            
            //  firmware
            sbDisplay.AppendLine();
            sbDisplay.Append("Firmware: ");

            ////  Serial Number
            //sbDisplay.AppendLine();
            //sbDisplay.Append("SerialNumber: ");
            //this.strSerialNumber = GetDeviceSerialNumber();
            //sbDisplay.Append(strSerialNumber);

            //  Get Channel Infos
            //  MessageBox.Show("Wait for a while to make it work");
            CHelpers.Pause(1000);
            CHelpers.Pause(1000);
            CHelpers.Pause(1000);
            CHelpers.Pause(1000);
            CHelpers.Pause(1000);

            //  number of coin values
            getHopperInformation();

            sbDisplay.AppendLine();
            sbDisplay.Append("Number of Coin Values: " + m_NumberOfChannels);
            sbDisplay.AppendLine();

            //  channel denominations
            sbDisplay.AppendLine();
            sbDisplay.Append("Channel Denominations");
            sbDisplay.AppendLine();

            //  Add channel data to list then display.
            //  Clear list.
            m_UnitDataList.Clear();
            int hopperIndex = 0;

            for (byte i = 0; i < m_NumberOfChannels; i++)
            {
                if (hopperIndex < hopperList.Count)
                {
                    __cpiHopper = hopperList[hopperIndex];
                }
                else
                {
                    __cpiHopper = null;
                }

                if  (__cpiHopper != null)
                {
                    ChannelData loopChannelData = new ChannelData();

                    //  Channel number.
                    loopChannelData.Channel =   (byte)(i + 1);

                    //  Channel Id
                    loopChannelData.ChannelId = __cpiHopper.HopperId;

                    //  Channel Value
                    loopChannelData.Value   =   __cpiHopper.CoinDenomination;

                    //  Channel currency.
                    char[] CurrencyArray    =   __cpiHopper.HopperCurrencyCode.ToCharArray();
                    loopChannelData.Currency[0] = (char)CurrencyArray[0];
                    loopChannelData.Currency[1] = (char)CurrencyArray[1];
                    loopChannelData.Currency[2] = (char)CurrencyArray[2];

                    //  Channel level.
                    loopChannelData.Level   =   __cpiHopper.value;

                    //  loopChannelData.Level = CheckCoinLevel(loopChannelData.Value, loopChannelData.Currency);

                    IsCoinRecycling(loopChannelData.Value, loopChannelData.Currency, ref loopChannelData.Recycling);

                    // Add data to list.
                    m_UnitDataList.Add(loopChannelData);

                    //  Display data
                    sbDisplay.Append("Channel ");
                    sbDisplay.Append(loopChannelData.Channel);
                    sbDisplay.Append(": ");
                    sbDisplay.Append(loopChannelData.Value / 100f);
                    sbDisplay.Append(" ");
                    sbDisplay.Append(loopChannelData.Currency);
                    sbDisplay.AppendLine();                    
                }

                hopperIndex++;
            }

            sbDisplay.AppendLine();

            //  Sort the list by .Value
            m_UnitDataList.Sort((d1, d2) => d1.Value.CompareTo(d2.Value));

            if (log != null)
                log.AppendText(sbDisplay.ToString());
        }

        byte[] hopperNoMask = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };

        /// <summary>
        ///     getNumberOfChannels
        /// </summary>
        /// <returns></returns>
        private void getNumberOfChannels()
        {
            byte    u8HopperByte = 0;
            int     result;
            int     hopperNo = 0x1;

            this.NumberOfChannels = 0;

            result = ClsApiClass.GetInstance().Cls_getOnlineHoppers(ref u8HopperByte);

            MessageBox.Show("Cls_getOnlineHoppers() call returns : " +
                ReturnValue.getStrReturnValue(result));

            if (result == ReturnValue.RET_SUCCESS)
            {
                //MessageBox.Show("Cls_getOnlineHoppers() call returns : " +
                //    ReturnValue.getStrReturnValue(result));
                //
                MessageBox.Show("Cls_getOnlineHoppers call returns : " + u8HopperByte);

                for (int i = 0; i < hopperNoMask.Length; i++)
                {
                    hopperNo = (i + 1);

                    if ((hopperNoMask[i] & u8HopperByte) != 0)
                    {
                        //  Hopper online
                        this.NumberOfChannels++;
                    }
                    else
                    {
                        //  Hopper offline
                    }
                }
            }                
        }

        /// <summary>
        ///     getHopperInformation
        /// </summary>
        /// <returns></returns>
        public int getHopperInformation()
        {
            byte    u8HopperByte = 0;
            int     result;
            int     hopperNo = 0x1;
            Hopper  hopper = null;

            this.m_NumberOfChannels = 0;

            result = ClsApiClass.GetInstance().Cls_getOnlineHoppers(ref u8HopperByte);

            //MessageBox.Show("Cls_getOnlineHoppers() call returns : " +
            //    ReturnValue.getStrReturnValue(result));

            Console.WriteLine("Cls_getOnlineHoppers() call returns : " +
                ReturnValue.getStrReturnValue(result));

            if  (result == ReturnValue.RET_SUCCESS)
            {
                Console.WriteLine("Cls_getOnlineHoppers call returns : " + u8HopperByte);

                for (int i = 0; i < hopperNoMask.Length; i++)
                {
                    hopperNo = (i + 1);

                    if ((hopperNoMask[i] & u8HopperByte) != 0)
                    {
                        m_NumberOfChannels++;

                        //  Hopper online
                        hopper = getDenominationInfoForHopper(hopperNo);

                        if (hopper != null)
                        {
                            addHopper(hopper);
                        }
                    }
                    else
                    {
                        //  Hopper offline
                    }
                }
            }
            else
            {

            }

            return 0;
        }

        /// <summary>
        ///     addHopper
        /// </summary>
        /// <param name="hopper"></param>
        /// <returns></returns>
        private int addHopper(Hopper hopper)
        {
            bool bFound = false;
            Hopper myHopper;

            //  Check for Hopper already exists
            foreach (Hopper _hopper in hopperList)
            {
                if (_hopper.HopperId == hopper.HopperId)
                {
                    //  Simply copy data
                    _hopper.CopyHopper(hopper);

                    bFound = true;
                    break;
                }
            }

            if (bFound)
            {
                return 0;
            }

            //--------------------Add--------------------------

            myHopper = new Hopper();
            myHopper.CopyHopper(hopper);

            hopperList.Add(myHopper);

            return 0;
        }

        /// <summary>
        ///     getDenominationInfoForHopper
        /// </summary>
        /// <param name="hopperNo"></param>
        /// <returns></returns>
        public Hopper getDenominationInfoForHopper(int hopperNo)
        {
            byte[]  pc8Iso = new byte[3];
            short   u16Denom = 0;
            short   u16InventoryValue = 0;
            byte    pc8Mint = 0;
            int     result;
            int     result_value;
            string  hopperCurrency;
            string  hopperMint;
            Hopper  myHopper;
            string  strContent;

            u16Denom = 0;

            for (int i = 0; i < 3; i++)
                pc8Iso[i] = 0;

            result = ClsApiClass.GetInstance().Cls_getDenominationFromHopperNo((byte)hopperNo,
                pc8Iso, ref u16Denom, ref pc8Mint);

            if (result == ReturnValue.RET_SUCCESS)
            {
                hopperCurrency = System.Text.Encoding.UTF8.GetString(pc8Iso);
                hopperMint = pc8Mint.ToString();

                //  Success
                myHopper = new Hopper();

                myHopper.HopperId = hopperNo;
                myHopper.HopperCurrencyCode = hopperCurrency;
                myHopper.CoinDenomination = u16Denom;
                myHopper.CoinMint = hopperMint;

                result_value = ClsApiClass.GetInstance().Cls_getHopperInventory((byte)hopperNo,
                    ref u16InventoryValue);

                if (result_value == ReturnValue.RET_SUCCESS)
                {
                    myHopper.value = u16InventoryValue;
                }
                else
                {
                    myHopper.value = 0;
                }

                return myHopper;
            }
            else
            {

            }

            return  null;
        }

        //  This function sends the set coin mech inhibits command to set which coins are accepted on the validator.
        //  Please Note: The response to this command if there is no coin mech attached will be WRONG PARAMETERS.
        public void SetInhibits(TextBox log = null)
        {
            // set inhibits on each coin           
        }

        /// <summary>
        ///     GetDeviceSerialNumber
        /// </summary>
        /// <returns></returns>
        private string GetDeviceSerialNumber()
        {
            int result;
            byte[] serialNumber = new byte[12];
            string strSerialNumber = string.Empty;

            result = ClsApiClass.GetInstance().Cls_getSerialNumber(serialNumber);

            if  (result == ReturnValue.RET_SUCCESS)
            { 
                strSerialNumber = System.Text.Encoding.UTF8.GetString(serialNumber);
            }
            else
            {
                strSerialNumber = "Unable to get";

                MessageBox.Show("Cls_getSerialNumber() call returns : " +
                    ReturnValue.getStrReturnValue(result));
            }

            return  strSerialNumber;
        }

        //  This function gets the serial number of the device.
        //  An optional Device parameter can be used
        //  for TEBS systems to specify which device's serial number should be returned.
        //  0x00 = NV200
        //  0x01 = SMART Payout
        //  0x02 = Tamper Evident Cash Box.
        public void GetSerialNumber(byte Device, TextBox log = null)
        {
            int result;
            bool bSuccess = false;
            byte[] serialNumber = new byte[12];
            string strSerialNumber = string.Empty;

            result = ClsApiClass.GetInstance().Cls_getSerialNumber(serialNumber);

            if  (result == ReturnValue.RET_SUCCESS)
            {
                bSuccess = true;

                strSerialNumber = System.Text.Encoding.UTF8.GetString(serialNumber);

                //  save info
                cls_ApiPaymentDevice.serialNumber = strSerialNumber;
            }

            if  (bSuccess && log != null)
            {
                log.AppendText("Serial Number ");
                log.AppendText(": ");
                log.AppendText(strSerialNumber);
                log.AppendText("\r\n");
            }
        }

        /// <summary>
        ///     GetSerialNumber
        /// </summary>
        /// <param name="log"></param>
        public void GetSerialNumber(TextBox log = null)
        {
            int     result;
            bool    bSuccess = false;
            byte[]  serialNumber = new byte[12];
            string  strSerialNumber = string.Empty;

            result = ClsApiClass.GetInstance().Cls_getSerialNumber(serialNumber);

            if  (result == ReturnValue.RET_SUCCESS)
            {
                bSuccess = true;

                strSerialNumber = System.Text.Encoding.UTF8.GetString(serialNumber);
            }

            if  (bSuccess && log != null)
            {
                log.AppendText("Serial Number ");
                log.AppendText(": ");
                log.AppendText(strSerialNumber);
                log.AppendText("\r\n");
            }
        }

        //  This function is called repeatedly to poll the validator about what events are happening. It
        //  can optionally output these events to a textbox.
        public bool DoPoll(TextBox log)
        {
            //  Poll System Events
            doPollSystemEvents(log);

            //  Poll Acceptor Events
            doPollAcceptorEvents(log);

            //  Poll Dispenser Events
            doPollDispenserEvents(log);

            return  true;
        }

        /// <summary>
        ///     doPollSystemEvents
        /// </summary>
        /// <param name="log"></param>
        private void doPollSystemEvents(TextBox log)
        {
            short numOfEvents = 0;
            int[] eventsList = new int[256];
            int result;

            for (int i = 0; i < eventsList.Length; i++)
            {
                eventsList[i] = 0x0;
            }

            result = ClsApiClass.GetInstance().Cls_pollSystemEvents(ref numOfEvents, eventsList);

            if  (result == ReturnValue.RET_SUCCESS)
            {
                //MessageBox.Show("Cls_pollSystemEvents call returns, numOfEvents = " + numOfEvents);

                if  (numOfEvents > 0)
                {
                    //  Dump all events to TextBox
                    dumpSystemEventsToTextBox(numOfEvents, eventsList, log);
                }
            }
        }

        /// <summary>
        ///     doPollAcceptorEvents
        /// </summary>
        /// <param name="log"></param>
        private void doPollAcceptorEvents(TextBox log)
        {
            short   numOfEvents = 0;
            int[]   eventsList = new int[256];
            int     result;

            for (int i = 0; i < eventsList.Length; i++)
            {
                eventsList[i] = 0x0;
            }

            result = ClsApiClass.GetInstance().Cls_pollAcceptorEvents(ref numOfEvents, eventsList);

            if  (result == ReturnValue.RET_SUCCESS)
            {
                //  MessageBox.Show("Cls_pollAcceptorEvents call returns, numOfEvents = " + numOfEvents);

                if  (numOfEvents > 0)
                {
                    //  Dump all events to TextBox
                    dumpAcceptorEventsToTextBox(numOfEvents, eventsList, log);

                    //  Update Data
                    UpdateData();
                }
            }
        }

        /// <summary>
        ///     doPollDispenserEvents
        /// </summary>
        /// <param name="log"></param>
        private void doPollDispenserEvents(TextBox log)
        {
            short   numOfEvents = 0;
            int[]   eventsList = new int[256];
            int     result;

            for (int i = 0; i < eventsList.Length; i++)
            {
                eventsList[i] = 0x0;
            }

            result = ClsApiClass.GetInstance().Cls_pollDispenserEvents(ref numOfEvents, eventsList);

            if (result == ReturnValue.RET_SUCCESS)
            {
                //  Console.WriteLine("Cls_pollDispenserEvents call returns, numOfEvents = " + numOfEvents);

                if  (numOfEvents > 0)
                {
                    //  Dump all events to TextBox
                    dumpDispenserEventsToTextBox(numOfEvents, eventsList, log);

                    //  Update
                    UpdateData();
                }
            }
        }

        /// <summary>
        ///     dumpSystemEventsToTextBox
        /// </summary>
        /// <param name="numOfEvents"></param>
        /// <param name="eventsList"></param>
        /// <param name="log"></param>
        /// <returns></returns>
        private int dumpSystemEventsToTextBox(int numOfEvents, int[] eventsList, TextBox log)
        {
            string  strContent = string.Empty;
            string  strEvent;
            string  strEventCategory;
            int     result;
            short   lower_16bits;
            byte    eventCategory = 0x0;
            byte[]  eventDesc = new byte[128];
            evt_Category evt_category;
            string  strEventDesc;

            for (int i = 0; i < numOfEvents; i++)
            {
                lower_16bits = (short)(eventsList[i] & 0xFFFF);

                result = ClsApiClass.GetInstance().Cls_lookupSystemEventCode(
                    lower_16bits, ref eventCategory, eventDesc);

                //  MessageBox.Show("Cls_lookupSystemEventCode call returns : " + 
                //      ReturnValue.getStrReturnValue(result));

                if (result == ReturnValue.RET_SUCCESS)
                {
                    //  eventCategory
                    if (Enum.IsDefined(typeof(evt_Category), (int)eventCategory))
                    {
                        evt_category = (evt_Category)Enum.ToObject(typeof(evt_Category), eventCategory);
                        strEventCategory = evt_category.ToString();
                    }
                    else
                    {
                        strEventCategory = eventCategory.ToString("X");
                    }

                    //  event Description
                    strEventDesc = System.Text.Encoding.UTF8.GetString(eventDesc);

                    //strContent += "Category : " + strEventCategory +
                    //    ",Desc = " + strEventDesc + Environment.NewLine;

                    strContent += strEventDesc + Environment.NewLine;
                }
                else
                {
                    strEvent = eventsList[i].ToString("X");

                    strContent += "0x" + strEvent + Environment.NewLine;
                }
            }

            if  (log != null)
            {
                log.AppendText(Environment.NewLine + strContent);
            }

            return  0;
        }

        /// <summary>
        ///     dumpDispenserEventsToTextBox
        /// </summary>
        /// <param name="numOfEvents"></param>
        /// <param name="eventsList"></param>
        /// <returns></returns>
        private int dumpDispenserEventsToTextBox(int numOfEvents, int[] eventsList, TextBox log)
        {
            string  strContent = string.Empty;
            string  strEvent;
            int     result;
            short   lower_16bits;
            string  strEventDesc;
            string  strEventCategory;
            byte    eventCategory = 0;
            byte[]  eventDesc = new byte[128];
            evt_Category evt_category;

            for (int i = 0; i < numOfEvents; i++)
            {
                lower_16bits = (short)(eventsList[i] & 0xFFFF);

                result = ClsApiClass.GetInstance().Cls_lookupDispenserEventCode(
                    lower_16bits, ref eventCategory, eventDesc);

                //  MessageBox.Show("Cls_lookupDispenserEventCode call returns : " +
                //      ReturnValue.getStrReturnValue(result));

                if  (result == ReturnValue.RET_SUCCESS)
                {
                    //  eventCategory
                    if  (Enum.IsDefined(typeof(evt_Category), (int)eventCategory))
                    {
                        evt_category = (evt_Category)Enum.ToObject(typeof(evt_Category), eventCategory);
                        strEventCategory = evt_category.ToString();
                    }
                    else
                    {
                        strEventCategory = eventCategory.ToString("X");
                    }

                    //  event Description
                    strEventDesc = System.Text.Encoding.UTF8.GetString(eventDesc);

                    //strContent += "Category : " + strEventCategory +
                    //    ",Desc = " + strEventDesc + Environment.NewLine;

                    strContent += strEventDesc + Environment.NewLine;
                }
                else
                {
                    strEvent = eventsList[i].ToString("X");

                    strContent += "0x" + strEvent + Environment.NewLine;
                }
            }

            if (log != null)
            {
                log.AppendText(strContent);
            }

            return  0;
        }

        /// <summary>
        ///     dumpAcceptorEventsToTextBox
        /// </summary>
        /// <param name="numOfEvents"></param>
        /// <param name="eventsList"></param>
        /// <param namee="log"></param>
        /// <returns></returns>
        private int dumpAcceptorEventsToTextBox(int numOfEvents, int[] eventsList, TextBox log)
        {
            string  strContent = string.Empty;
            string  strEvent;
            string  strEventCategory;
            short   lower_16bits;
            int     result;
            byte    eventCategory = 0x0;
            byte[]  eventDesc = new byte[128];
            evt_Category evt_category;
            string  strEventDesc;

            for (int i = 0; i < numOfEvents; i++)
            {
                lower_16bits = (short)(eventsList[i] & 0xFFFF);

                eventCategory = 0;
                for (int j = 0; j < 128; j++)
                    eventDesc[j] = 0;

                result = ClsApiClass.GetInstance().Cls_lookupAcceptorEventCode(
                    lower_16bits, ref eventCategory, eventDesc);

                //MessageBox.Show("Cls_lookupAcceptorEventCode call returns : " +
                //    ReturnValue.getStrReturnValue(result));

                if  (result == ReturnValue.RET_SUCCESS)
                {
                    //  eventCategory
                    if  (Enum.IsDefined(typeof(evt_Category), (int)eventCategory))
                    {
                        evt_category = (evt_Category)Enum.ToObject(typeof(evt_Category), eventCategory);
                        strEventCategory = evt_category.ToString();
                    }
                    else
                    {
                        strEventCategory = eventCategory.ToString("X");
                    }

                    //  event Description
                    strEventDesc = System.Text.Encoding.UTF8.GetString(eventDesc);

                    //strContent += "Category : " + strEventCategory +
                    //    ",Desc = " + strEventDesc + Environment.NewLine;

                    strContent += strEventDesc + Environment.NewLine;
                }
                else
                {
                    strEvent = eventsList[i].ToString("X");

                    strContent += "0x" + strEvent + Environment.NewLine;
                }
            }

            if  (log != null)
            {
                log.AppendText(Environment.NewLine + strContent);
            }

            return  0;
        }

        //  Non-Command functions 
        //  Use the library handler to open the port
        public bool OpenPort()
        {
            int result;

            result = ClsApiClass.GetInstance().Cls_OpenApi();

            if  (result == ReturnValue.RET_SUCCESS)
            {
                Console.WriteLine("OpenApi Success");

                return  true;
            }           

            return  false;
        }

        //  This returns the currency of a specified channel.
        public char[] GetChannelCurrency(int channel)
        {
            if  (channel > 0 && channel <= m_NumberOfChannels)
            {
                foreach (ChannelData d in m_UnitDataList)
                {
                    if  (d.Channel == channel)
                        return  d.Currency;
                }
            }

            return  null;
        }

        //  This returns the level of a specified channel.
        public int GetChannelLevel(int channel)
        {
            if (channel > 0 && channel <= m_NumberOfChannels)
            {
                foreach (ChannelData d in m_UnitDataList)
                {
                    if (d.Channel == channel)
                        return  d.Level;
                }
            }

            return -1;
        }

        //  This is similar to the above function but instead returns
        //  all the channels as a nicely formatted string
        public string GetChannelLevelInfo()
        {
            string s = "";
            
            foreach (ChannelData d in m_UnitDataList)
            {
                s += (d.Value / 100f).ToString() + " " + d.Currency[0] + d.Currency[1] + d.Currency[2];
                s += " [" + d.Level + "] = " + ((d.Level * d.Value) / 100f).ToString();
                s += " " + d.Currency[0] + d.Currency[1] + d.Currency[2] + "\r\n";
            }

            return  s;
        }

        //  This takes a coin value and returns the channel number
        public int GetChannelofCoin(int coin)
        {
            foreach (ChannelData d in m_UnitDataList)
            {
                if  (d.Value == coin)
                    return  d.Channel;
            }

            return  -1;
        }

        /// <summary>
        ///     closeApi
        /// </summary>
        /// <returns></returns>
        public int closeApi()
        {
            int result = ClsApiClass.GetInstance().Cls_CloseApi();

            return  result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public CoinStatus getCoinStatus()
        {
            int coinsStored = 0;
            int collectableCoinValue = 0;
            int coinsCashbox = 0;

            CoinStatus coinStatus = new CoinStatus();

            for (int i = 0; i < m_UnitDataList.Count; i++)
            {
                ChannelData d = m_UnitDataList[i];

                coinsStored += d.Level * d.Value;
            }

            collectableCoinValue += coinsStored + coinsCashbox;

            coinStatus.coinsStored          =   coinsStored;
            coinStatus.collectableCoinValue =   collectableCoinValue;
            coinStatus.coinsCashbox         =   coinsCashbox;

            return  coinStatus;
        }

        /// <summary>
        ///     buildApiPaymentDeviceForCpiHopper
        /// </summary>
        /// <returns></returns>
        public ApiPaymentDevice buildApiPaymentDeviceForCpiHopper()
        {            
            //  Build Fake Api PaymentDevice
            //  buildFakeApiPaymentDevice();

            //  Build Real Api PaymentDevice
            buildRealApiPaymentDevice();

            return  cls_ApiPaymentDevice;
        }

        /// <summary>
        ///     buildRealApiPaymentDevice
        /// </summary>
        private void buildRealApiPaymentDevice()
        {
            ApiDenomination apiDenomination;
            ApiCashboxDenomination apiCashboxDenomination;

            //  Common Part
            cls_ApiPaymentDevice.datasetVersion = "TBD";
            cls_ApiPaymentDevice.serialNumber = "0000508557";
            cls_ApiPaymentDevice.firmwareVersion = "$MOD$ 180220 1101.0004 CLS_HOPR.BTR";
            cls_ApiPaymentDevice.countryCode = "SAR";
            cls_ApiPaymentDevice.paymentType = "Coins";
            cls_ApiPaymentDevice.isConnected = true;

            //  Denomination List
            for(int i = 0; i < m_UnitDataList.Count; i++)
            {
                ChannelData d = m_UnitDataList[i];
              
                if (d.Recycling)
                {
                    apiDenomination = new ApiDenomination();

                    apiDenomination.country = "SAR";
                    apiDenomination.value = d.Value;
                    apiDenomination.route = "Payout";
                    apiDenomination.storedLevel = d.Level;
                    apiDenomination.storedValue = d.Level * d.Value;
                    apiDenomination.floatLevel = 0;
                    apiDenomination.maxStoredLevel = 0;
                    apiDenomination.enabled = true;

                    cls_ApiPaymentDevice.denominations.Add(apiDenomination);
                }
                else
                {
                    apiCashboxDenomination = new ApiCashboxDenomination();

                    apiCashboxDenomination.country = "SAR";
                    apiCashboxDenomination.value = d.Value;
                    apiCashboxDenomination.storedLevel = d.Level;
                    apiCashboxDenomination.storedValue  = d.Level* d.Value;

                    cls_ApiPaymentDevice.cashboxDenominations.Add(apiCashboxDenomination);
                }                
            }
        }

        /// <summary>
        ///     buildFakeApiPaymentDevice
        /// </summary>
        private void buildFakeApiPaymentDevice()
        {
            ApiDenomination apiDenomination1;
            ApiDenomination apiDenomination5;
            ApiDenomination apiDenomination10;
            ApiDenomination apiDenomination25;
            ApiDenomination apiDenomination50;
            ApiDenomination apiDenomination100;
            ApiDenomination apiDenomination200;

            cls_ApiPaymentDevice.datasetVersion     =   "TBD";
            cls_ApiPaymentDevice.serialNumber       =   "0000508557";
            cls_ApiPaymentDevice.firmwareVersion    =   "$MOD$ 180220 1101.0004 CLS_HOPR.BTR";
            cls_ApiPaymentDevice.countryCode        =   "SAR";
            cls_ApiPaymentDevice.paymentType        =   "Coins";
            cls_ApiPaymentDevice.isConnected        =   true;
            cls_ApiPaymentDevice.storedValue        =   2;

            //  ApiDenomination 1
            apiDenomination1 = new ApiDenomination();
            apiDenomination1.country                =   "SAR";
            apiDenomination1.value                  =   1;
            apiDenomination1.route                  =   "Payout";
            apiDenomination1.storedLevel            =   0;
            apiDenomination1.storedValue            =   0;
            apiDenomination1.floatLevel             =   0;
            apiDenomination1.maxStoredLevel         =   0;
            apiDenomination1.enabled                =   true;
            cls_ApiPaymentDevice.denominations.Add(apiDenomination1);

            //  ApiDenomination 5
            apiDenomination5 = new ApiDenomination();
            apiDenomination5.country                =   "SAR";
            apiDenomination5.value                  =   5;
            apiDenomination5.route                  =   "Payout";
            apiDenomination5.storedLevel            =   0;
            apiDenomination5.storedValue            =   0;
            apiDenomination5.floatLevel             =   0;
            apiDenomination5.maxStoredLevel         =   0;
            apiDenomination5.enabled                =   true;
            cls_ApiPaymentDevice.denominations.Add(apiDenomination5);

            //  ApiDenomination 10
            apiDenomination10 = new ApiDenomination();
            apiDenomination10.country = "SAR";
            apiDenomination10.value = 10;
            apiDenomination10.route = "Payout";
            apiDenomination10.storedLevel = 0;
            apiDenomination10.storedValue = 0;
            apiDenomination10.floatLevel = 0;
            apiDenomination10.maxStoredLevel = 0;
            apiDenomination10.enabled = true;
            cls_ApiPaymentDevice.denominations.Add(apiDenomination10);

            //  ApiDenomination 25
            apiDenomination25 = new ApiDenomination();
            apiDenomination25.country = "SAR";
            apiDenomination25.value = 25;
            apiDenomination25.route = "Payout";
            apiDenomination25.storedLevel = 1;
            apiDenomination25.storedValue = 25;
            apiDenomination25.floatLevel = 0;
            apiDenomination25.maxStoredLevel = 0;
            apiDenomination25.enabled = true;
            cls_ApiPaymentDevice.denominations.Add(apiDenomination25);

            //  ApiDenomination 50
            apiDenomination50 = new ApiDenomination();
            apiDenomination50.country = "SAR";
            apiDenomination50.value = 50;
            apiDenomination50.route = "Payout";
            apiDenomination50.storedLevel = 0;
            apiDenomination50.storedValue = 0;
            apiDenomination50.floatLevel = 0;
            apiDenomination50.maxStoredLevel = 0;
            apiDenomination50.enabled = true;
            cls_ApiPaymentDevice.denominations.Add(apiDenomination50);

            //  ApiDenomination 100
            apiDenomination100 = new ApiDenomination();
            apiDenomination100.country = "SAR";
            apiDenomination100.value = 100;
            apiDenomination100.route = "Payout";
            apiDenomination100.storedLevel = 0;
            apiDenomination100.storedValue = 0;
            apiDenomination100.floatLevel = 0;
            apiDenomination100.maxStoredLevel = 0;
            apiDenomination100.enabled = true;
            cls_ApiPaymentDevice.denominations.Add(apiDenomination100);

            //  ApiDenomination 200
            apiDenomination200 = new ApiDenomination();
            apiDenomination200.country = "SAR";
            apiDenomination200.value = 200;
            apiDenomination200.route = "Payout";
            apiDenomination200.storedLevel = 1;
            apiDenomination200.storedValue = 200;
            apiDenomination200.floatLevel = 0;
            apiDenomination200.maxStoredLevel = 0;
            apiDenomination200.enabled = true;
            cls_ApiPaymentDevice.denominations.Add(apiDenomination200);
        }
    }
}
